package cn.com.egova.erp.dao.impl;

import cn.com.egova.erp.dao.IBaseDao;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * Created by yuanchao on 2020/6/4.
 */
public class BaseDao<T> extends HibernateDaoSupport implements IBaseDao<T> {
    /**
     * 泛型中的初阶类型
     */
    private Class<T> entityClass;

    public BaseDao() {
        //获取对象对应的父类的类型
        Type baseDaoClass = this.getClass().getGenericSuperclass();
        //转成带参数，即泛型的类型
        ParameterizedType pType = (ParameterizedType) baseDaoClass;
        //获取参数泛型类型数组
        Type[] types = pType.getActualTypeArguments();
        //由于我们的BaseDao<T>的泛型参数里只有一个类型T，因此数组的第一个元素就是类型T的实际上的类型
        this.entityClass = (Class<T>) types[0];
    }

    /**
     * 条件查询
     *
     * @param t1
     * @param t2
     * @param param
     * @return
     */
    @Override
    public List<T> getList(T t1, T t2, Object param) {
        DetachedCriteria criteria = getDetachedCriteria(t1, t2, param);
        return (List<T>) this.getHibernateTemplate().findByCriteria(criteria);
    }

    /**
     * 分页查询
     *
     * @param t1
     * @param t2
     * @param param
     * @param firstResult
     * @param maxResults
     * @return
     */
    @Override
    public List<T> getListByPage(T t1, T t2, Object param, int firstResult, int maxResults) {
        DetachedCriteria criteria = getDetachedCriteria(t1, t2, param);
        return (List<T>) this.getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults);
    }

    /**
     * 记录条件查询的总记录数
     *
     * @param t1
     * @param t2
     * @param param
     * @return
     */
    @Override
    public long getCount(T t1, T t2, Object param) {
        DetachedCriteria criteria = getDetachedCriteria(t1, t2, param);
        criteria.setProjection(Projections.rowCount());
        List<Long> list = (List<Long>) this.getHibernateTemplate().findByCriteria(criteria);
        return list.get(0);
    }

    /**
     * 新增
     *
     * @param t
     */
    @Override
    public void add(T t) {
        this.getHibernateTemplate().save(t);
    }

    /**
     * 删除
     *
     * @param uuid
     */
    @Override
    public void delete(Long uuid) {
        //让对象进入持久化状态
        T t = this.getHibernateTemplate().get(entityClass, uuid);
        //删除持久化状态
        this.getHibernateTemplate().delete(t);
    }


    /**
     * 通过编号查询对象
     *
     * @param uuid
     * @return
     */
    @Override
    public T get(Long uuid) {
        return this.getHibernateTemplate().get(entityClass, uuid);
    }


    /**
     * 通过字符串主键获取对象
     *
     * @param uuid
     * @return
     */
    @Override
    public T get(String uuid) {
        return getHibernateTemplate().get(entityClass, uuid);
    }

    @Override
    public void update(T t) {
        this.getHibernateTemplate().update(t);
    }


    /**
     * 根据uuid获取对应的名称
     *
     * @param uuid
     * @param nameMap    用于缓存
     * @param methodName
     * @return
     */
    @Override
    public String getName(Long uuid, Map<Long, String> nameMap, String methodName) {
        try {
            String name = nameMap.get(uuid);
            if (name == null) {
                //获取实体类的class对象
                ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
                Class clazz = (Class) parameterizedType.getActualTypeArguments()[0];
                //获取将要调用实体类的方法对象
                Method method = clazz.getMethod(methodName, null);
                //查询数据库得到对应的实例
                Object obj = this.get(uuid);
                //调用方法
                name = (String) method.invoke(obj, null);
                nameMap.put(uuid, name);
            }
            return name;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 由子类实现
     *
     * @param t1
     * @return
     */
    public DetachedCriteria getDetachedCriteria(T t1, T t2, Object param) {

        return null;
    }
}
